package com.zmn.plat.business.impl.channel;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.nacos.api.config.annotation.NacosValue;
import com.google.common.base.Joiner;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.zmn.account.common.constant.AccountMqConsts;
import com.zmn.account.common.constant.IdentityConsts;
import com.zmn.account.common.dto.account.OpenAccountDIO;
import com.zmn.common.constant.GlobalConsts;
import com.zmn.common.dictionary.DictModel;
import com.zmn.common.dictionary.GlobalDict;
import com.zmn.common.dto.KvDTO;
import com.zmn.common.dto2.ResponseDTO;
import com.zmn.common.utils.MethodSignUtils;
import com.zmn.common.utils.collection.CollectionUtil;
import com.zmn.common.utils.date.DateUtil;
import com.zmn.common.utils.number.NumberUtil;
import com.zmn.common.utils.pinyin.PinYinUtil;
import com.zmn.common.utils.reflect.BeanMapper;
import com.zmn.common.utils.string.StringUtil;
import com.zmn.framework.core.http.HttpClientsFactory;
import com.zmn.framework.mq.ZmnMQException;
import com.zmn.manager.mq.interfaces.ZmnMQSender;
import com.zmn.manager.redis.lock.DistributedLock;
import com.zmn.manager.redis.lock.DistributedLockUtils;
import com.zmn.mcc.cas.model.LoginStaff;
import com.zmn.mcc.cas.web.StaffAdminService;
import com.zmn.mcc.dubbo.dto.DubboConsts;
import com.zmn.plat.business.interfaces.channel.ChannelBService;
import com.zmn.plat.business.interfaces.channel.ChannelServiceCategoryBService;
import com.zmn.plat.business.interfaces.msg.MsgDingTalkBsService;
import com.zmn.plat.common.constant.ChannelConsts;
import com.zmn.plat.common.constant.OnePriceConsts;
import com.zmn.plat.common.constant.ProductConsts;
import com.zmn.plat.common.constant.RedisKeyConstant;
import com.zmn.plat.common.dictionary.*;
import com.zmn.plat.common.dto.area.AreaSimpleDRO;
import com.zmn.plat.common.dto.channel.ChannelBrandSiteAddDIO;
import com.zmn.plat.common.dto.channel.ChannelDIO;
import com.zmn.plat.common.dto.channel.ChannelDRO;
import com.zmn.plat.common.exception.PlatException;
import com.zmn.plat.common.util.CompareObjectUtil;
import com.zmn.plat.manager.dictionary.ChannelDict;
import com.zmn.plat.model.dto.channel.ChannelSettleDTO;
import com.zmn.plat.model.entity.area.BaseArea;
import com.zmn.plat.model.entity.category.BaseCategory;
import com.zmn.plat.model.entity.category.BaseCategoryQuery;
import com.zmn.plat.model.entity.category.CategoryInfoDTO;
import com.zmn.plat.model.entity.channel.*;
import com.zmn.plat.model.entity.channel.generalproduct.ChannelGeneralProductSwitch;
import com.zmn.plat.model.entity.channel.order.config.ChannelOrderConfig;
import com.zmn.plat.model.entity.channel.settle.ChannelMergeSettle;
import com.zmn.plat.model.entity.company.BaseCompany;
import com.zmn.plat.model.entity.product.ServProduct;
import com.zmn.plat.model.entity.product.ServProductQuery;
import com.zmn.plat.model.entity.servcategory.ServAssCategory;
import com.zmn.plat.model.entity.servcategory.ServAssCategoryQuery;
import com.zmn.plat.model.entity.servcategory.ServCategory;
import com.zmn.plat.model.vo.area.AreaSimpleVO;
import com.zmn.plat.model.vo.channel.ChannelCityPriceRatioVo;
import com.zmn.plat.model.vo.servcategory.CategotyVO;
import com.zmn.plat.model.vo.servcategory.ServAssCategoryVO;
import com.zmn.plat.services.interfaces.area.BaseAreaService;
import com.zmn.plat.services.interfaces.category.BaseCategoryService;
import com.zmn.plat.services.interfaces.channel.*;
import com.zmn.plat.services.interfaces.channel.generalproduct.ChannelGeneralProductSwitchService;
import com.zmn.plat.services.interfaces.channel.order.config.ChannelOrderConfigService;
import com.zmn.plat.services.interfaces.channel.settle.ChannelMergeSettleService;
import com.zmn.plat.services.interfaces.company.BaseCompanyService;
import com.zmn.plat.services.interfaces.product.ServProductService;
import com.zmn.plat.services.interfaces.servcategory.ServAssCategoryService;
import com.zmn.plat.services.interfaces.servcategory.ServCategoryService;
import com.zmn.uuc.common.constant.PassConsts;
import com.zmn.uuc.common.dio.pass.IdentityBaseOperateDIO;
import com.zmn.uuc.common.dio.pass.PassIdentityBaseDIO;
import com.zmn.uuc.dubbo.interfaces.pass.PassModifyRemoteService;
import lombok.extern.log4j.Log4j2;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cglib.beans.BeanCopier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static java.util.stream.Collectors.groupingBy;

@Service
@Log4j2
public class ChannelBServiceImpl implements ChannelBService {

    public static final String NAME_EXIST_MESSAGE = "渠道名称已存在! 请更换其他名称!";
    public static final String ANOTHER_NAME_EXIST_MESSAGE = "渠道别名已存在! 请更换其他名称!";

    /**
     * 省parentId
     */
    public static final int AREA_PARENTID = 1;
    public static final String LOG_TYPE_UPDATE = "修改";
    public static final String TAB_QDXX = "渠道信息";
    public static final String TAB_DDPZ = "订单配置";
    public static final String TAB_KTFL = "开通分类";
    public static final String TAB_KTCP = "开通产品";
    public static final String TAB_KTQY = "开通区域";
    public static final String TAB_KTQY_YCQY = "开通区域";
    public static final String TAB_KTQY_KTFL = "开通区域";
    public static final String TAB_KTQY_XGDT = "开通区域";
    public static final String TAB_FWGCS = "服务工程师";
    public static final String TAB_BWJG = "保外价格";
    public static final String TAB_BNJG = "保内价格";
    public static final String TAB_GCJG = "工程价格";
    public static final String TAB_JSXX = "结算信息";
    public static final String TAB_YJGL = "押金管理";
    public static final String TAB_YJSZ = "佣金设置";
    public static final String TAB_BZJGL = "保证金管理";

    private static final Integer AREA_CITY_LEVEL = 3;

    /**
     * 默认审核起始金额100元-10000分
     */
    private static final Integer DEFAULT_AUDIT_MIN_PRICE = 10000;

    /**
     * 首次用户保护期：默认90天
     */
    private static final Integer DEFAULT_FRIST_PROTECTED_PERIOD = 90;

    /**
     * 用户活跃保护期：默认7天
     */
    private static final Integer DEFAULT_LATELY_PROTECTED_PERIOD = 7;

    /**
     * 发送结算周期变动mq的topic
     */
    @Value("${spring.mq.topic.erp:zmn_erp}")
    private String countCycleMqTopic;

    @NacosValue(value = "${spring.mq.topic.account}", autoRefreshed = true)
    public String platTopicAccount;

    @NacosValue(value = "${cc.remote.api.secret}", autoRefreshed = true)
    private String ccApiSecret;

    @NacosValue(value = "${cc.remote.api.uri}", autoRefreshed = true)
    private String ccApiUri;

    @Value("${spring.mq.topic.cds:zmn_cds}")
    private String cdsMqTopic;


    /**
     * 渠道结算周期配置
     */
    public static final String ERP_CHANNEL_STATEMENT_CONFIG_MQ_TAG = "mq_channel_statement_config_tag";


    public static final String CDS_CHANNEL_CLOSED_MQ_TAG = "mq_channel_closed_msg_tag";

    @Autowired
    private ChannelService channelService;

    @Resource
    private ChannelOrderConfigService channelOrderConfigService;

    @Autowired
    private ChannelServiceCategoryService categoryService;

    @Autowired
    private ChannelGeneralProductSwitchService channelGeneralProductSwitchService;

    @Autowired
    private ChannelServiceAreaCategoryService areaCategoryService;

    @Autowired
    private ChannelDepositService depositService;

    @Autowired
    private ChannelDepositLogService depositLogService;

    @Autowired
    private ChannelServiceAreaService serviceAreaService;

    @Autowired
    private BaseAreaService baseAreaService;

    @Autowired
    private ChannelSettleService settleService;

    @Resource
    ZmnMQSender zmnMQSender;

    @Autowired
    private ServAssCategoryService servAssCategoryService;

    @Autowired
    private ChannelCommissionService commissionService;

    @Autowired
    private BaseCompanyService baseCompanyService;

    @Autowired
    private ServCategoryService servCategoryService;

    @Autowired
    private ChannelCityPriceRatioService cityPriceRatioService;

    @Autowired
    private ServProductService servProductService;

    @Autowired
    private BaseCategoryService baseCategoryService;

    @Autowired
    private ChannelLogService channelLogService;

    @Resource
    private ChannelServiceCategoryBService channelServiceCategoryBService;

    @Resource
    private RedisTemplate<String, String> redisTemplate;

    @Resource
    private ChannelMergeSettleService mergeSettleService;

    @Resource
    private MsgDingTalkBsService msgDingTalkBsService;

    @Reference(version = DubboConsts.INTERFACE_VERSION, check = false)
    private PassModifyRemoteService passModifyRemoteService;

    @Override
    public ChannelDRO getByChannelId(Integer channelId) {

        if (Objects.isNull(channelId)) {
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PANAM_NULL);
        }
        String key = RedisKeyConstant.getKeyChannelDro(channelId);
        String value = redisTemplate.opsForValue().get(key);
        // 缓存中有数据
        if (StringUtil.isNotBlank(value)) {
            if (RedisKeyConstant.NO_DATA.equals(value)) {
                return null;
            } else {
                return JSONObject.parseObject(value, ChannelDRO.class);
            }
        }
        int time = 60;
        String lockKey = RedisKeyConstant.getLockKeyChannelDro(channelId);
        DistributedLock redisLock = DistributedLockUtils.buildReentrantLock(lockKey, time);
        if (redisLock.tryLock()) {
            try {
                ChannelDRO dro;
                Channel channel = channelService.findByKey(channelId);
                if (channel == null) {
                    value = RedisKeyConstant.NO_DATA;
                    dro = null;
                } else {
                    dro = BeanMapper.map(channel, ChannelDRO.class);
                    String parentSourceName = channelService.findNameByKey(dro.getParentSourceId());
                    dro.setParentSourceName(parentSourceName);
                    value = JSONObject.toJSONString(dro);
                }
                redisTemplate.opsForValue().set(key, value, 5, TimeUnit.MINUTES);
                return dro;
            } finally {
                try {
                    redisLock.unlock();
                } catch (Exception ignored) {
                }
            }
        } else {
            if (redisLock.lock(time, TimeUnit.SECONDS)) {
                try {
                    redisLock.unlock();
                } catch (Exception ignored) {
                }
                return getByChannelId(channelId);
            } else {
                log.error("获取渠道信息，获取redis锁超时");
                throw new PlatException(PlatErrorCodeDict.ERROR_CODE_TIME_OUT);
            }
        }

    }

    @Override
    public List<Channel> listChannelVtByQuery(Integer staffId, Integer plat, Integer type, Integer channelOneDeptId, Integer channelDeptId, Integer parentId, Integer status) {
        return listChannelVtByQuery(staffId, plat, type, channelOneDeptId, channelDeptId, parentId, status, null);
    }

    @Override
    public List<Channel> listChannelVtByQuery(Integer staffId, Integer plat, Integer type, Integer channelOneDeptId, Integer channelDeptId, Integer parentId, Integer status, String keyword) {
        ChannelQuery query = new ChannelQuery() {
            {
                setPlat(plat);
                setChannelType(type);
                setOneDeptId(channelOneDeptId);
                setDeptId(channelDeptId);
                setParentId(parentId);
                setStatus(status);
                setLikeName(keyword);
                if (NumberUtil.isPositiveInteger(staffId)) {
                    setOperatorId(staffId);
                }
            }
        };
        List<Channel> channels = channelService.listByQuery(query);
        return channels;
    }

    @Override
    public List<AreaSimpleDRO> listAreaByChannelId(Integer channelId) {
        if (Objects.isNull(channelId)) {
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PANAM_NULL);
        }

        try {
            channelId = channelServiceCategoryBService.getAvailableCategoryChannelId(channelId);
        } catch (PlatException e) {
            List<AreaSimpleVO> baseAreaList = baseAreaService.listAllCitySimpleVo();

            List<AreaSimpleDRO> result = baseAreaList.stream().map(areaSimpleVO -> {
                AreaSimpleDRO areaSimpleDRO = new AreaSimpleDRO();
                BeanUtils.copyProperties(areaSimpleVO, areaSimpleDRO);
                return areaSimpleDRO;
            }).collect(Collectors.toList());

            return result;
        }

        List<AreaSimpleVO> areaSimpleVOList = baseAreaService.listAreaByChannelId(channelId);

        List<AreaSimpleDRO> result = areaSimpleVOList.stream().map(areaSimpleVO -> {
            AreaSimpleDRO areaSimpleDRO = new AreaSimpleDRO();
            BeanUtils.copyProperties(areaSimpleVO, areaSimpleDRO);
            return areaSimpleDRO;
        }).collect(Collectors.toList());

        return result;
    }

    @Override
    public void listByDimissionChannel() throws Exception {
        List<Channel> list = channelService.listByDimissionChannel();
        msgDingTalkBsService.dimissionChannelSendMessage(list);

    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addChannel(ChannelAddVO channel, LoginStaff mcStaff) {
        if (StringUtil.isBlank(channel.getCreater())) {
            channel.setCreater("SYSTEM");
            channel.setUpdater("SYSTEM");
        }

        // 新增渠道
        addChannelInfo(channel);

        // 发送渠道消息给资金账户开户
        sendChannelOpenAccount(channel, GlobalConsts.NO, mcStaff);

        // 初始化渠道订单配置
        addChannelOrderConfig(channel);

        if (channel.getParentId() != null) {
            // redis key 删除
            String parentKey = RedisKeyConstant.getKeyParentChannelDro(channel.getParentId());
            redisTemplate.delete(parentKey);
        }
    }

    /**
     * 描述:
     *
     */
    @Override
    public void addChannelOrderConfig(ChannelAddVO channel){
        ChannelOrderConfig channelOrderConfig = null;

        // 只有二级渠道新增时才初始化订单配置数据，一级渠道不需要：by章科
        if (Objects.equals(ChannelDict.RANK_TWO, channel.getRank())) {
            channelOrderConfig = new ChannelOrderConfig();
            if (Objects.equals(ChannelTypeEnum.CJ.getCode(), channel.getChannelType())) {
                channelOrderConfig.setInReceivablesLimit(Optional.ofNullable(channel.getInReceivablesLimit()).orElse(ChannelReceivablesLimitEnum.CONSTS_XDYF));
                channelOrderConfig.setOutReceivablesLimit(Optional.ofNullable(channel.getOutReceivablesLimit()).orElse(ChannelReceivablesLimitEnum.CONSTS_GCS));
            }

            channelOrderConfig.setPayer(channel.getPayer());
            channelOrderConfig.setPrepayType(Optional.ofNullable(channel.getPrepayType()).orElse(GlobalConsts.NO));
            channelOrderConfig.setCheckSp(Optional.ofNullable(channel.getCheckSp()).orElse(GlobalConsts.NO));
            channelOrderConfig.setTransType(Optional.ofNullable(channel.getTransType()).orElse(GlobalConsts.NO));
            channelOrderConfig.setCodeEntry(Optional.ofNullable(channel.getCodeEntry()).orElse(GlobalConsts.NO));
            String workOrderType = ChannelWorkOrderTypeEnum.CONSTS_YYHT + "," + ChannelWorkOrderTypeEnum.CONSTS_GCSAPP + "," + ChannelWorkOrderTypeEnum.CONSTS_FWSMH;
//            channelOrderConfig.setWorkOrderCompleteType(Optional.ofNullable(channel.getWorkOrderCompleteType()).orElse(workOrderType));
            channelOrderConfig.setWorkOrderCancelType(Optional.ofNullable(channel.getWorkOrderCancelType()).orElse(workOrderType));
//            channelOrderConfig.setWorkOrderSpecialOfferType(Optional.ofNullable(channel.getWorkOrderSpecialOfferType()).orElse(workOrderType));

            if (Objects.equals(ChannelTypeEnum.CJ.getCode(), channel.getChannelType())) {
                channelOrderConfig.setApplique(Optional.ofNullable(channel.getApplique()).orElse(GlobalConsts.NO));
            } else {
                channelOrderConfig.setApplique(Optional.ofNullable(channel.getApplique()).orElse(GlobalConsts.YES));
            }

            channelOrderConfig.setShowOrderPrice(Optional.ofNullable(channel.getShowOrderPrice()).orElse(GlobalConsts.YES));
            //后台录单  若接入方式为 API、H5 默认不允许
            List<Integer> accessModeArray = StringUtil.split(channel.getAccessMode(), ",", Integer.class);
            if (accessModeArray.contains(ChannelConsts.CHANNEL_ACCESS_MODE_H5) || accessModeArray.contains(ChannelConsts.CHANNEL_ACCESS_MODE_API)) {
                // 不允许
                channelOrderConfig.setHidden(GlobalConsts.NO);//
            } else {
                channelOrderConfig.setHidden(Optional.ofNullable(channel.getHidden()).orElse(GlobalConsts.YES));//
            }
            channelOrderConfig.setSendMsg(Optional.ofNullable(channel.getSendMsg()).orElse(GlobalConsts.YES));
            if (StringUtil.isNotBlank(channel.getAccessMode()) && channel.getAccessMode().indexOf(ChannelConsts.CHANNEL_ACCESS_MODE_API) != -1) {
                channelOrderConfig.setPlatformType(Optional.ofNullable(channel.getPlatformType()).orElse(GlobalConsts.NO));
            } else {
                channelOrderConfig.setPlatformType(Optional.ofNullable(channel.getPlatformType()).orElse(GlobalConsts.YES));
            }
            channelOrderConfig.setOrderTransferType(Optional.ofNullable(channel.getOrderTransferType()).orElse(GlobalConsts.YES));

            // by章科：若是厂商渠道，则默认是：F端需审核，并且审核起始金额为：0
            if (Objects.equals(ChannelTypeEnum.CJ.getCode(), channel.getChannelType())) {
                channelOrderConfig.setAuditType(Optional.ofNullable(channel.getAuditType()).orElse(GlobalConsts.YES));
                channelOrderConfig.setAuditMinPrice(Optional.ofNullable(channel.getAuditMinPrice()).orElse(GlobalConsts.NONE));
            } else {
                channelOrderConfig.setAuditType(Optional.ofNullable(channel.getAuditType()).orElse(GlobalConsts.NO));
                channelOrderConfig.setAuditMinPrice(Optional.ofNullable(channel.getAuditMinPrice()).orElse(DEFAULT_AUDIT_MIN_PRICE));
            }

            channelOrderConfig.setNotifyEngineer(Optional.ofNullable(channel.getNotifyEngineer()).orElse(GlobalConsts.YES));
            //channelOrderConfig.setFristProtectedPeriod(Optional.ofNullable(channel.getFristProtectedPeriod()).orElse(DEFAULT_FRIST_PROTECTED_PERIOD));
            channelOrderConfig.setLatelyProtectedPeriod(Optional.ofNullable(channel.getLatelyProtectedPeriod()).orElse(DEFAULT_LATELY_PROTECTED_PERIOD));

            channelOrderConfig.setCreateTime(channel.getCreateTime());
            channelOrderConfig.setCreater(channel.getCreater());
            channelOrderConfig.setUpdateTime(channel.getCreateTime());
            channelOrderConfig.setUpdater(channel.getCreater());
        }

        if (!Objects.isNull(channelOrderConfig)) {
            channelOrderConfig.setChannelId(channel.getChannelId());
            channelOrderConfigService.insert(channelOrderConfig);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Channel addBrandSiteChannel(ChannelBrandSiteAddDIO channelBrandSiteAddDIO) {
        Channel channel = new Channel();
        BeanCopier copier = BeanCopier.create(ChannelBrandSiteAddDIO.class, Channel.class, false);
        copier.copy(channelBrandSiteAddDIO, channel, null);
        channel.setParentSourceId(channelBrandSiteAddDIO.getParentId());
        channel.setCreater("SYSTEM");
        channel.setUpdater("SYSTEM");
        channel.setCreateTime(DateUtil.getNow());
        channel.setUpdateTime(DateUtil.getNow());

        addBrandSiteChannelInfo(channel);

        return channel;
    }

    @Override
    public void addCpsChannel(Channel channel) {
        // 啄金客业务已经暂停
        // if (channel.getParentId() == null || channel.getParentId().equals(ChannelDict.CPS_PARENTID)) {
        // // 设置啄金客二级渠道默认值
        // Consumer<Channel> setDefault = (obj) -> {
        // obj.setPlat(GlobalConsts.PLAT_MARK_ZMN);
        // obj.setRank(ChannelDict.RANK_TWO);
        // obj.setParentId(ChannelDict.CPS_PARENTID);
        // obj.setChannelType(com.zmn.plat.common.dictionary.ChannelTypeEnum.CONSTS_TG);
        // obj.setLevel(com.zmn.plat.common.dictionary.ChannelLevelEnum.PT.getCode());
        // obj.setAccessMode(null);
        // obj.setContact(channel.getName());
        // obj.setOneDeptId(ChannelDict.CPS_ONE_DEPTID);
        // obj.setOneDeptName(ChannelDict.CPS_ONE_DEPTNAME);
        // obj.setDeptId(ChannelDict.CPS_DEPTID);
        // obj.setDeptName(ChannelDict.CPS_DEPTNAME);
        // obj.setCheckCompanyBank(GlobalConsts.YES);
        // String rl = com.zmn.plat.common.dictionary.ChannelReceivablesEnum.GCS.getCode().toString() + "," +
        // com.zmn.plat.common.dictionary.ChannelReceivablesEnum.PT.getCode().toString() + "," +
        // com.zmn.plat.common.dictionary.ChannelReceivablesEnum.QD.getCode().toString();
        // obj.setReceivablesLimit(rl);
        // obj.setApplique(GlobalConsts.YES);
        // obj.setPrepayType(GlobalConsts.NO);
        // obj.setShowOrderPrice(GlobalConsts.YES);
        // obj.setHidden(GlobalConsts.YES);
        // obj.setSendMsg(GlobalConsts.YES);
        // obj.setPlatformType(GlobalConsts.NO);
        // obj.setOrderTransferType(GlobalConsts.YES);
        // obj.setChannelProductNameShowType(GlobalConsts.NO);
        // };
        // setDefault.accept(channel);
        // }
        // addChannelInfo(channel);
    }

    private void addChannelInfo(Channel channel) {
        // 校验渠道信息
        checkChannelInfo(channel, null);

        if (channel.getRank() == null) {
            channel.setRank(ChannelDict.RANK_TWO);
        }

        if (channel.getRank() == ChannelDict.RANK_ONE) {
            channel.setParentId(ChannelDict.RANK_ONE);
        }

        if (channel.getStatus() == null || channel.getStatus() == 0) {
            channel.setStatus(GlobalConsts.NO);
        }

        if (channel.getRank() == ChannelDict.RANK_TWO && !NumberUtil.isNullOrZero(channel.getParentId())) {
            Channel parent = channelService.findByKey(channel.getParentId());
            if (parent != null) {
                channel.setParentName(parent.getName());
            }
        }

        setPinyin(channel);

        // 如果合同模式为空 根据所选平台确定合同模式
        if (NumberUtil.isNullOrZero(channel.getContractModel())) {
            if (NumberUtil.isNotNullOrZero(channel.getPlat()) && Objects.equals(channel.getPlat(), GlobalConsts.PLAT_MARK_ZMN)) {
                channel.setContractModel(ChannelConsts.PLAT_COLLECTION_CONTRACT_MODE);
            } else {
                channel.setContractModel(ChannelConsts.REPAIT_SERVICE_CONTRACT_MODE);
            }
        }

        // 新增渠道
        channelService.insert(channel);

        if (channel.getRank() == ChannelDict.RANK_TWO) {
            addChannelSettle(channel);
            // 新增佣金比例
            ServCategory query = new ServCategory();
            query.setStatus(GlobalDict.STATUS_ENABLE);
            List<ServCategory> servCategoryList = servCategoryService.listByQuery(query);
            for (ServCategory servCategory : servCategoryList) {
                ChannelCommission commission = new ChannelCommission();
                commission.setChannelId(channel.getChannelId());
                commission.setCommissionCurrent(0f);
                commission.setCommissionType(1);
                commission.setBaseType(2);
                commission.setServCategId(servCategory.getCategId());
                commission.setServCategName(servCategory.getName());
                commission.setCreater(channel.getCreater());
                commission.setUpdater(channel.getCreater());
                commissionService.insert(commission);
            }
        }
    }

    @Override
    public void addChannelSettle(Channel channel){
        ChannelSettle settle = new ChannelSettle();
        settle.setChannelId(channel.getChannelId());
        settle.setPlat(channel.getPlat());
        // modify 新增默认为权责发生制 1收付实现制,2权责发生制
        settle.setFinancialRules(com.zmn.plat.common.dictionary.ChannelFinancialRulesEnum.CONSTS_ZQ);
        settle.setCreater(channel.getCreater());
        settle.setCreateTime(channel.getCreateTime());
        // 新增结算信息
        this.modifySettle(settle, channel.getCreater());

        ServAssCategoryQuery categoryQuery = new ServAssCategoryQuery();
        categoryQuery.setCategOneStatus(GlobalConsts.YES);
        categoryQuery.setCategTwoStatus(GlobalConsts.YES);
        categoryQuery.setServCategStatus(GlobalConsts.YES);
        categoryQuery.setShowType(ProductConsts.EC_PRODUCT_TYPE);
        List<ServAssCategoryVO> twoVoList = servAssCategoryService.listByQuery(categoryQuery);
        List<String> twoCategoryIds = twoVoList.stream().map(this::servToStr).collect(Collectors.toList());
        // 新增前台服务区域
        this.addChannelServiceCategory(channel.getChannelId(), ProductConsts.EC_PRODUCT_TYPE, twoCategoryIds, channel.getCreater());
    }

    /**
     * 新增品牌站渠道信息
     *
     * @param channel
     */
    private void addBrandSiteChannelInfo(Channel channel) {
        // 校验渠道信息
        checkChannelInfo(channel, null);

        if (channel.getRank() == null) {
            channel.setRank(ChannelDict.RANK_TWO);
        }

        if (channel.getRank() == ChannelDict.RANK_ONE) {
            channel.setParentId(ChannelDict.RANK_ONE);
        }

        if (!Objects.equals(channel.getStatus(), GlobalConsts.NO)) {
            channel.setStatus(GlobalConsts.YES);
        }

        if (channel.getRank() == ChannelDict.RANK_TWO && !NumberUtil.isNullOrZero(channel.getParentId())) {
            Channel parent = channelService.findByKey(channel.getParentId());
            if (parent != null) {
                channel.setParentName(parent.getName());
                if (Objects.isNull(channel.getCompanyId())) {
                    channel.setCompanyId(parent.getCompanyId());
                    channel.setCompanyName(parent.getCompanyName());
                }
            }
        }

        setPinyin(channel);

        // 如果合同模式为空 根据所选平台确定合同模式
        if (NumberUtil.isNullOrZero(channel.getContractModel())) {
            if (NumberUtil.isNotNullOrZero(channel.getPlat()) && Objects.equals(channel.getPlat(), GlobalConsts.PLAT_MARK_ZMN)) {
                channel.setContractModel(ChannelConsts.PLAT_COLLECTION_CONTRACT_MODE);
            } else {
                channel.setContractModel(ChannelConsts.REPAIT_SERVICE_CONTRACT_MODE);
            }
        }

        // 新增渠道
        channelService.insert(channel);
    }

    private void checkChannelInfo(Channel channel, Integer excludeChannelId) {
        if (channel.getCheckCompanyBank() != null && channel.getCheckCompanyBank() == GlobalConsts.YES && NumberUtil.isNotNullOrZero(channel.getCompanyId())) {
            // 校验公司银行卡信息
            checkCompanyBankInfo(channel.getCompanyId());
        }
        // 校验渠道名称存在
        checkNameExist(excludeChannelId, p -> p.setName(channel.getName().trim()), NAME_EXIST_MESSAGE);
        if (StringUtil.isNotBlank(channel.getAnotherName())) {
            // 校验别名存在
            checkNameExist(excludeChannelId, p -> p.setAnotherName(channel.getAnotherName().trim()), ANOTHER_NAME_EXIST_MESSAGE);
        }
    }

    private void checkCompanyBankInfo(Integer companyId) {
        BaseCompany byKey = baseCompanyService.findByKey(companyId);
        if (byKey == null) {
            throw new PlatException("选择所属公司不存在！");
        }
        if (StringUtil.isBlank(byKey.getBankName()) || StringUtil.isBlank(byKey.getBankCardName()) || StringUtil.isBlank(byKey.getBankCardNo())) {
            throw new PlatException("请完善所属公司对应银行卡信息！");
        }
    }

    private void checkNameExist(Integer excludeChannelId, Consumer<ChannelQuery> setName, String existMessage) {
        ChannelQuery query = new ChannelQuery();
        setName.accept(query);
        List<Channel> channels = channelService.listByQuery(query);
        if (excludeChannelId != null && channels != null) {
            channels = channels.stream().filter(p -> !Objects.equals(p.getChannelId(), excludeChannelId)).collect(Collectors.toList());
        }
        if (channels != null && channels.size() > 0) {
            throw new PlatException(existMessage);
        }
    }

    private void setPinyin(Channel channel) {
        String name = channel.getName();
        String anotherName = channel.getAnotherName();
        if (StringUtil.isNotBlank(name)) {
            String s = PinYinUtil.stringToPinyin(name, ",");
            channel.setNamePinyin(s);
        }
        if (StringUtil.isNotBlank(anotherName)) {
            String s = PinYinUtil.stringToPinyin(anotherName, ",");
            channel.setAnotherNamePinyin(s);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void modifyBaseInfoByKey(Channel channel, LoginStaff mcStaff) {

        Channel before = findByKey(channel.getChannelId());

        // 校验渠道信息
        checkChannelInfo(channel, channel.getChannelId());
        if (channel.getRank() == ChannelDict.RANK_ONE) {
            channel.setParentId(ChannelDict.RANK_ONE);
        }
        setPinyin(channel);
        // 针对*的不做修改
        if (StringUtil.isNotBlank(channel.getMobile()) && channel.getMobile().indexOf("*") != -1) {
            channel.setMobile(before.getMobile());
        }
        channelService.updateBaseInfoByKey(channel);

        // 发送渠道消息给资金账户开户
        sendChannelOpenAccount(channel, GlobalConsts.YES, mcStaff);

        Channel after = findByKey(channel.getChannelId());
        getsTheSourceChannelName(before, after);
        String[] compareContentData = getCompareContentData(before, after);
        createLog(before.getChannelId(), before.getName(), TAB_QDXX, compareContentData[1], channel.getRemark());

        // redis key 删除
        String key = RedisKeyConstant.getKeyChannelDro(channel.getChannelId());
        String parentKey = RedisKeyConstant.getKeyParentChannelDro(channel.getParentId());
        if (channel.getParentId() == null) {
            redisTemplate.delete(key);
        } else {
            List<String> keyList = Arrays.asList(key, parentKey);
            redisTemplate.delete(keyList);
        }
    }

    private Channel findByKey(Integer channelId) {
        return channelService.findByKey(channelId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void modifyOrderConfig(ChannelOrderConfig channelOrderConfig) {
        ChannelOrderConfig orderConfig = channelOrderConfigService.findByKey(channelOrderConfig.getChannelId());
        String operator = StaffAdminService.currentStaff().getRealName();
        Date now = DateUtil.getNow();
        if (Objects.isNull(orderConfig)) {
            channelOrderConfig.setCreater(operator);
            channelOrderConfig.setCreateTime(now);
            channelOrderConfig.setUpdater(operator);
            channelOrderConfig.setUpdateTime(now);
            channelOrderConfigService.insert(channelOrderConfig);
        } else {
            ChannelOrderConfig before = channelOrderConfigService.findByKey(channelOrderConfig.getChannelId());
            channelOrderConfig.setUpdater(operator);
            channelOrderConfig.setUpdateTime(now);
            channelOrderConfigService.updateByKey(channelOrderConfig);
            ChannelOrderConfig after = channelOrderConfigService.findByKey(channelOrderConfig.getChannelId());
            String[] compareContentData = getCompareContentData(before, after);
            createLog(before.getChannelId(), null, TAB_DDPZ, compareContentData[1], channelOrderConfig.getRemark());
            // redis key 删除
            String key = RedisKeyConstant.getKeyChannelOrderConfigDro(channelOrderConfig.getChannelId());
            redisTemplate.delete(key);
        }
    }

    @Override
    public void updateByKeySelective(Channel channel) {
        Channel before = findByKey(channel.getChannelId());

        // 如果合同模式为空 根据所选平台确定合同模式
        if (NumberUtil.isNullOrZero(channel.getContractModel())) {
            if (NumberUtil.isNotNullOrZero(channel.getPlat()) && Objects.equals(channel.getPlat(), GlobalConsts.PLAT_MARK_ZMN)) {
                channel.setContractModel(ChannelConsts.PLAT_COLLECTION_CONTRACT_MODE);
            } else {
                channel.setContractModel(ChannelConsts.REPAIT_SERVICE_CONTRACT_MODE);
            }
        }

        channelService.updateByKeySelective(channel);
        Channel after = findByKey(channel.getChannelId());
        String[] compareContentData = getCompareContentData(before, after);
        createLog(before.getChannelId(), before.getName(), TAB_QDXX, compareContentData[1]);
    }

    @Override
    public void updateInnerName(Channel record) {
        Channel before = findByKey(record.getChannelId());
        channelService.updateByKeySelective(record);
        Channel after = findByKey(record.getChannelId());
        String[] compareContentData = getCompareContentData(before, after);
        createLog(before.getChannelId(), before.getName(), TAB_QDXX, compareContentData[1]);
    }

    @Override
    public void updateSortByKey(Integer channelId, Integer sort, String mcStaffName) {
        Channel before = findByKey(channelId);
        channelService.updateSortByKey(channelId, sort, mcStaffName);
        Channel after = findByKey(channelId);
        String[] compareContentData = getCompareContentData(before, after);
        createLog(before.getChannelId(), before.getName(), TAB_DDPZ, compareContentData[1]);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void modifyStatusByIds(List<Integer> channelIds, Integer status, String updater) {
        Map<Integer, Channel> beforesMap = channelService.listByChannelIds(channelIds).stream().collect(Collectors.toMap(Channel::getChannelId, item -> item));
        channelService.updateStatusByIds(channelIds, status, updater);
        Map<Integer, Channel> aftersMap = channelService.listByChannelIds(channelIds).stream().collect(Collectors.toMap(Channel::getChannelId, item -> item));
//        for (Integer channelId : channelIds) {
//            EsChannel esChannel = new EsChannel();
//            esChannel.setChannelId(channelId);
//            esChannel.setStatus(status);
//
//            Channel before = beforesMap.get(channelId);
//            Channel after = aftersMap.get(channelId);
//            String[] compareContentData = getCompareContentData(before, after);
//            createLog(before.getChannelId(), before.getName(), TAB_QDXX, compareContentData[1]);
//        }

        if (Objects.equals(status, ChannelDict.STATUS_HIDDEN)) {

            // 渠道关闭关闭钉钉消息
            msgDingTalkBsService.channelCloseSendMessage(channelIds);
            // 通知CC
            noticeToCC(channelIds);
            // 通知UUC
            noticeToUUC(channelIds, updater);

        }

        // 通知cds
        Map<String, Object> closedMsg = new HashMap<>();
        closedMsg.put("channelIds", channelIds);
        closedMsg.put("status", status);
        zmnMQSender.send(cdsMqTopic, CDS_CHANNEL_CLOSED_MQ_TAG, StringUtil.getRandomsString(32),
                JSON.toJSONString(closedMsg));

    }


    /**
     * 描述: 渠道关闭通知CC
     *
     * @param channelIds
     * @author jiafei
     * @since 2021/8/4 9:35
     */
    private void noticeToCC(List<Integer> channelIds) {

        try {
            // 渠道关闭关闭向cc发送消息
            log.info("渠道：{}关闭关联关闭CC路线,开始……", JSON.toJSONString(channelIds));
            Map<String, String> params = Maps.newHashMap();
            params.put("channelIds", Joiner.on(",").join(channelIds));
            params.put("sign", MethodSignUtils.sign(params, ccApiSecret));
            HttpClientsFactory.getHttpClients().postForm(ccApiUri.concat("/open/channels/disableChannels"), params);
            log.info("渠道：{}关闭关联关闭CC路线,完成……", JSON.toJSONString(channelIds));
        } catch (Exception e) {
            log.error("关闭关联关闭CC路线失败", e);
        }
    }

    /**
     * 描述: 渠道关闭通知UUC
     *
     * @param channelIds
     * @param updater
     * @author jiafei
     * @since 2021/8/4 9:34
     */
    private void noticeToUUC(List<Integer> channelIds, String updater) {

        try {
            // 渠道关闭关闭通知 渠道客户关闭
            log.info("渠道:{}关闭通知uuc;开始……", JSON.toJSONString(channelIds));
            IdentityBaseOperateDIO identityBaseOperateDIO = new IdentityBaseOperateDIO();
            List<PassIdentityBaseDIO> identityList = new ArrayList<>();
            channelIds.forEach(channelId -> {
                PassIdentityBaseDIO passIdentityBaseDIO = new PassIdentityBaseDIO();
                passIdentityBaseDIO.setIdentityType(PassConsts.PASS_IDENTITY_TYPE_CHANNEL);
                passIdentityBaseDIO.setIdentityObjectId(Long.valueOf(channelId));
                identityList.add(passIdentityBaseDIO);
            });
            identityBaseOperateDIO.setIdentityBaseDIOList(identityList);
            identityBaseOperateDIO.setOperator(updater);
            ResponseDTO<Boolean> responseDTO = passModifyRemoteService.disableIdentity(identityBaseOperateDIO);
            log.info("渠道:{}关闭通知uuc;结束……，结果:{}", JSON.toJSONString(channelIds), JSON.toJSONString(responseDTO));
        } catch (Exception e) {
            log.error("关闭通知uuc失败", e);
        }
    }

    @Override
    public void updateStatusByKey(Channel channel) {

        Channel before = findByKey(channel.getChannelId());
        channelService.updateStatusByKey(channel);
        Channel after = findByKey(channel.getChannelId());
        String[] compareContentData = getCompareContentData(before, after);
        createLog(before.getChannelId(), before.getName(), TAB_QDXX, compareContentData[1]);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void modifyChannelServiceCategory(Integer channelId, Integer servCategId, Integer status, Integer showType, List<String> categoryIds, String operator) {
        if (channelId == null) {
            return;
        }

        // 需要校验 所选择的服务分类+二级产品分类下是否有已上架的前台产品
        judgeUpProduct(servCategId, showType, categoryIds);

        List<String> dbCategorys = categoryService.listByChannelIdAndServCategId(channelId, servCategId, showType).stream()
                .map(item -> item.getServCategId() + "-" + item.getCategOneId() + "-" + item.getCategId()).collect(Collectors.toList());

        // 过滤渠道新开通分类
        List<String> openCategoryIds = categoryIds.stream().filter(item -> !dbCategorys.contains(item)).collect(Collectors.toList());
        openOrCloseAreaCategory(channelId, showType, operator, openCategoryIds, true);

        // 过滤渠道关闭的分类
        List<String> colseCategoryIds = dbCategorys.stream().filter(item -> !categoryIds.contains(item)).collect(Collectors.toList());
        openOrCloseAreaCategory(channelId, showType, operator, colseCategoryIds, false);

        categoryService.deleteByChannelIdAndServiceId(channelId, servCategId, showType);
        List<ChannelServiceCategory> insertBatch = new ArrayList<>(categoryIds.size());
        categoryIds.forEach(categoryId -> {
            String[] ids = categoryId.split("-");
            ChannelServiceCategory serviceCategory =
                    new ChannelServiceCategory(null, channelId, showType, Integer.valueOf(ids[0]), Integer.valueOf(ids[1]), Integer.valueOf(ids[2]), operator, null, DateUtil.getNow(), null);
            insertBatch.add(serviceCategory);
        });

        if (insertBatch != null && insertBatch.size() > 0) {
            categoryService.insertBatch(insertBatch);
        }

        ChannelGeneralProductSwitch channelGeneralProductSwitch = channelGeneralProductSwitchService.findByChannelIdAndServCategId(channelId, servCategId);
        if (channelGeneralProductSwitch == null) {
            ChannelGeneralProductSwitch insert = new ChannelGeneralProductSwitch();
            insert.setChannelId(channelId);
            insert.setServCategId(servCategId);
            insert.setStatus(status);
            insert.setCreateTime(DateUtil.getNow());
            insert.setCreater(operator);
            insert.setUpdateTime(DateUtil.getNow());
            insert.setUpdater(operator);
            channelGeneralProductSwitchService.insert(insert);
        } else {
            channelGeneralProductSwitch.setUpdater(operator);
            channelGeneralProductSwitch.setUpdateTime(DateUtil.getNow());
            channelGeneralProductSwitch.setStatus(status);
            channelGeneralProductSwitchService.updateByKey(channelGeneralProductSwitch);
        }

        createLog(channelId, null, TAB_KTFL, null);

        // 删除redis key
        String availableCategoryKey = RedisKeyConstant.getKeyAvailableCategoryByChannelId(channelId);
        String serverCategoryKey = RedisKeyConstant.getKeyServerCategoryByChannelIdAndShowType(channelId, showType);
        redisTemplate.delete(Arrays.asList(availableCategoryKey, serverCategoryKey));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @SuppressWarnings("Duplicates")
    public void addChannelServiceCategory(Integer channelId, Integer showType, List<String> categoryIds, String operator) {
        if (channelId == null) {
            return;
        }
        List<String> dbCategorys =
                categoryService.listByChannelId(channelId, showType).stream().map(item -> servToStr(item)).collect(Collectors.toList());

        // 过滤渠道新开通分类
        List<String> openCategoryIds = categoryIds.stream().filter(item -> !dbCategorys.contains(item)).collect(Collectors.toList());
        openOrCloseAreaCategory(channelId, showType, operator, openCategoryIds, true);

        // 过滤渠道关闭的分类
        List<String> colseCategoryIds = dbCategorys.stream().filter(item -> !categoryIds.contains(item)).collect(Collectors.toList());
        openOrCloseAreaCategory(channelId, showType, operator, colseCategoryIds, false);

        categoryService.deleteByChannelId(channelId, showType);
        List<ChannelServiceCategory> insertBatch = new ArrayList<>(categoryIds.size());
        List<Integer> servCategIds = new ArrayList<>();
        categoryIds.forEach(categoryId -> {
            String[] ids = categoryId.split("-");
            ChannelServiceCategory serviceCategory =
                    new ChannelServiceCategory(null, channelId, showType, Integer.valueOf(ids[0]), Integer.valueOf(ids[1]), Integer.valueOf(ids[2]), operator, operator, DateUtil.getNow(), DateUtil.getNow());
            insertBatch.add(serviceCategory);
            if (!servCategIds.contains(Integer.valueOf(ids[0]))) {
                servCategIds.add(Integer.valueOf(ids[0]));
            }
        });

        if (insertBatch != null && insertBatch.size() > 0) {
            categoryService.insertBatch(insertBatch);
        }

        // 新增渠道：开通通用产品开关默认开启
        List<ChannelGeneralProductSwitch> switchBatch = new ArrayList<>(categoryIds.size());
        servCategIds.forEach(servCategId -> {
            ChannelGeneralProductSwitch switchObj = new ChannelGeneralProductSwitch();
            switchObj.setChannelId(channelId);
            switchObj.setServCategId(servCategId);
            switchObj.setStatus(GlobalConsts.YES);
            switchObj.setCreater(operator);
            switchObj.setCreateTime(DateUtil.getNow());
            switchObj.setUpdater(operator);
            switchObj.setUpdateTime(DateUtil.getNow());
            switchBatch.add(switchObj);
        });

        channelGeneralProductSwitchService.insertBatch(switchBatch);
    }

    /**
     * 需要校验 所选择的服务分类+二级产品分类下是否有已上架的前台产品
     *
     * @param servCategId
     * @param showType
     * @param categoryIds
     */
    private void judgeUpProduct(Integer servCategId, Integer showType, List<String> categoryIds) {
        ServProductQuery servProductQuery = new ServProductQuery();
        servProductQuery.setShowType(showType);
        servProductQuery.setServCategId(servCategId);
        servProductQuery.setStatus(GlobalConsts.YES);
        List<ServProduct> servProducts = servProductService.listByQuery(servProductQuery);
        List<String> upProductCategIds = servProducts.stream().map(item -> servToStr(item)).collect(Collectors.toList());
        List<String> tipsCategIds = categoryIds.stream().filter(item -> !upProductCategIds.contains(item)).collect(Collectors.toList());
        List<Integer> twoCategoryIds = new ArrayList<>();
        if (tipsCategIds != null && tipsCategIds.size() > 0) {
            for (String tipsCategId : tipsCategIds) {
                String[] ids = tipsCategId.split("-");
                twoCategoryIds.add(Integer.valueOf(ids[2]));
            }
            BaseCategoryQuery baseCategoryQuery = new BaseCategoryQuery();
            baseCategoryQuery.setCategIds(twoCategoryIds);
            List<BaseCategory> baseCategories = baseCategoryService.listByQuery(baseCategoryQuery);
            StringBuffer tips = new StringBuffer();
            for (int i = 0; i < baseCategories.size(); i++) {
                tips.append(baseCategories.get(i).getName());
                if (i < baseCategories.size() - 1) {
                    tips.append("、");
                }
            }

            String productTipStr = "";
            if (showType.equals(ProductConsts.ERP_PRODUCT_TYPE)) {
                productTipStr = "后台产品";
            } else {
                productTipStr = "前台产品";
            }

            throw new PlatException(String.format("【<span style='color:red;'>%s</span>】产品分类下无上架的%s，请在对应产品分类下添加上架的%s", tips.toString(), productTipStr, productTipStr));
        }
    }

    private void openOrCloseAreaCategory(Integer channelId, Integer showType, String operator, List<String> categoryIds, boolean isOpen) {
        if (categoryIds.size() > 0) {

            List<Integer> servCategIds = categoryIds.stream().map(item -> item.split("-")[0]).map(Integer::valueOf).collect(Collectors.toList());
            List<Integer> categIds = categoryIds.stream().map(item -> item.split("-")[2]).map(Integer::valueOf).collect(Collectors.toList());
            // 查询渠道服务区域已存在的分类
            List<ChannelServiceAreaCategory> dbAreaCategoryList = areaCategoryService.listByChannelIdAndShowTypeAndServCategIdsAndCategIds(channelId, showType, servCategIds, categIds);
            List<Integer> dbAreaCategoryIds = dbAreaCategoryList.stream().map(ChannelServiceAreaCategory::getId).collect(Collectors.toList());

            if (!CollectionUtils.isEmpty(dbAreaCategoryIds)) {
                // 删除渠道服务区域已存在的分类
                areaCategoryService.deleteByKeys(dbAreaCategoryIds);
            }

            if (isOpen) {
                // 查询存在分类配置的服务区域ID
                List<Integer> serviceAreaIds = areaCategoryService.listServiceAreaIdByChannelIdAndShowType(channelId, showType);

                if (!CollectionUtils.isEmpty(serviceAreaIds)) {
                    // 渠道新开通分类, 服务区域对应开通分类
                    List<ChannelServiceAreaCategory> areaCategoryList = serviceAreaIds.stream().map(serviceAreaId -> {

                        Stream<ChannelServiceAreaCategory> s = categoryIds.stream().map(categoryId -> {
                            String[] ids = categoryId.split("-");
                            return new ChannelServiceAreaCategory(null, serviceAreaId, channelId, showType, Integer.valueOf(ids[0]), Integer.valueOf(ids[1]), Integer.valueOf(ids[2]), operator, null,
                                    DateUtil.getNow(), null);
                        });
                        return s;
                    }).flatMap(list -> list).collect(Collectors.toList());
                    areaCategoryService.insertBatch(areaCategoryList);
                }
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void modifyChannelServiceAreaCategory(Integer serviceAreaId, Integer servCategId, Integer channelId, Integer showType, List<String> categoryIds, String operator) {
        if (serviceAreaId == null || channelId == null) {
            return;
        }

        // 需要校验 所选择的服务分类+二级产品分类下是否有已上架的前台产品
        judgeUpProduct(servCategId, showType, categoryIds);

        areaCategoryService.deleteByServiceAreaIdAndServCategId(serviceAreaId, servCategId, showType);
        List<ChannelServiceAreaCategory> insertBatch = new ArrayList<>(categoryIds.size());
        categoryIds.forEach(categoryId -> {
            String[] ids = categoryId.split("-");
            ChannelServiceAreaCategory serviceCategory = new ChannelServiceAreaCategory(null, serviceAreaId, channelId, showType, Integer.valueOf(ids[0]), Integer.valueOf(ids[1]),
                    Integer.valueOf(ids[2]), operator, null, DateUtil.getNow(), null);
            insertBatch.add(serviceCategory);
        });
        if (insertBatch.size() > 0) {
            areaCategoryService.insertBatch(insertBatch);
        }
        ChannelServiceArea serviceArea = new ChannelServiceArea();
        serviceArea.setServiceAreaId(serviceAreaId);
        serviceArea.setUpdater(operator);
        serviceArea.setUpdateTime(DateUtil.getNow());
        serviceAreaService.updateByKey(serviceArea);

        createLog(channelId, null, TAB_KTQY_KTFL, null);
    }

    @Override
    public void batchModifyChannelServiceAreaCategory(ChannelBatchAreaServCategoryVO batchAreaServCategoryVO) {
        Integer servCategId = batchAreaServCategoryVO.getServCategId();
        Integer showType = batchAreaServCategoryVO.getShowType();
        Integer channelId = batchAreaServCategoryVO.getChannelId();
        String operator = batchAreaServCategoryVO.getOperator();
        List<Integer> serviceAreaIds = batchAreaServCategoryVO.getServiceAreaIdList();
        List<String> categoryIds = StringUtil.isBlank(batchAreaServCategoryVO.getCategoryId()) ? Collections.EMPTY_LIST : Arrays.asList(batchAreaServCategoryVO.getCategoryId().split(","));
        if (CollectionUtils.isEmpty(serviceAreaIds) || Objects.isNull(channelId) || NumberUtil.isNullOrZero(showType) || NumberUtil.isNullOrZero(servCategId) || CollectionUtils.isEmpty(categoryIds)) {
            log.error("参数不能为空：batchAreaServCategoryVO：{}", batchAreaServCategoryVO);
            return;
        }

        // 需要校验 所选择的服务分类+二级产品分类下是否有已上架的前台产品
        judgeUpProduct(servCategId, showType, categoryIds);

        areaCategoryService.deleteByServiceAreaIdsAndServCategId(serviceAreaIds, servCategId, showType);
        List<ChannelServiceAreaCategory> insertBatch = new ArrayList<>(categoryIds.size());
        serviceAreaIds.forEach(e -> {
            categoryIds.forEach(categoryId -> {
                String[] ids = categoryId.split("-");
                ChannelServiceAreaCategory serviceCategory =
                        new ChannelServiceAreaCategory(null, e, channelId, showType, Integer.valueOf(ids[0]), Integer.valueOf(ids[1]), Integer.valueOf(ids[2]), operator, null, DateUtil.getNow(), null);
                insertBatch.add(serviceCategory);
            });
        });

        if (CollectionUtil.isNotNullOrEmpty(insertBatch)) {
            areaCategoryService.insertBatch(insertBatch);
        }

        serviceAreaService.updateBatch(operator, serviceAreaIds);

        createLog(channelId, null, TAB_KTQY_KTFL, null);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void inOrOutDeposit(Integer channelId, Integer type, Integer amount, String operator, String remark) {
        ChannelDeposit deposit = depositService.findByKey(channelId);
        if (deposit == null) {
            if (type == ChannelConsts.CHANNEL_DEPOSIT_TYPE_RECHARGE) {
                deposit = new ChannelDeposit(channelId, amount, operator, operator, DateUtil.getNow(), DateUtil.getNow());
                depositService.insert(deposit);
            } else {
                throw new PlatException("无押金可退!");
            }
        } else {
            if (type == ChannelConsts.CHANNEL_DEPOSIT_TYPE_REFUND || type == ChannelConsts.CHANNEL_DEPOSIT_TYPE_DEDUCTION) {
                // 退款取负数
                amount = amount * -1;
                int balance = deposit.getBalance() + amount;
                if (balance < 0) {
                    throw new PlatException((type == ChannelConsts.CHANNEL_DEPOSIT_TYPE_REFUND ? "退款" : "扣款") + "金额大于当前押金余额!");
                }
            }

            depositService.addBalance(channelId, amount);
        }
        deposit = depositService.findByKey(channelId);
        ChannelDepositLog depositLog = new ChannelDepositLog(null, channelId, type, amount, deposit.getBalance(), remark, operator, operator, DateUtil.getNow(), DateUtil.getNow());
        depositLogService.insert(depositLog);
        createLog(channelId, null, TAB_YJGL, null);
        // redis key 删除
        String key = RedisKeyConstant.getKeyChannelDeposit(channelId);
        redisTemplate.delete(key);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addServiceArea(List<Integer> areaIds, Integer channelId, String operator) {

        if (areaIds == null || areaIds.size() == 0 || channelId == null || channelId == 0) {
            throw new PlatException("参数错误!");
        }

        List<Integer> provinceIds = baseAreaService.listByParentId(AREA_PARENTID).stream().map(BaseArea::getAreaId).collect(Collectors.toList());

        areaIds = areaIds.stream().flatMap(areaId -> {
            if (provinceIds.contains(areaId)) {
                // 存在省份id转换城市id
                return baseAreaService.listByParentId(areaId).stream().map(BaseArea::getAreaId);
            } else {
                return Stream.of(areaId);
            }
        }).collect(Collectors.toList());

        // 城市重复删除
        List<ChannelServiceArea> cityList = serviceAreaService.listCountryIsNull(channelId, areaIds);
        if (cityList != null && cityList.size() > 0) {
            List<Integer> cityIds = cityList.stream().map(ChannelServiceArea::getCityId).distinct().collect(Collectors.toList());
            areaIds = areaIds.stream().filter(p -> !cityIds.contains(p)).collect(Collectors.toList());
        }

        if (areaIds == null || areaIds.size() == 0 || channelId == null || channelId == 0) {
            throw new PlatException("数据已存在! 不需要填加");
        }

        // 区县重复删除
        List<ChannelServiceArea> countryList = serviceAreaService.listByChannelIdAndCountryIds(channelId, areaIds);
        if (countryList != null && countryList.size() > 0) {
            List<Integer> countryIds = countryList.stream().map(ChannelServiceArea::getCountryId).distinct().collect(Collectors.toList());
            areaIds = areaIds.stream().filter(p -> !countryIds.contains(p)).collect(Collectors.toList());
        }

        if (areaIds == null || areaIds.size() == 0 || channelId == null || channelId == 0) {
            throw new PlatException("数据已存在! 不需要填加");
        }

        // 查询新增区域对象
        List<BaseArea> areas = baseAreaService.findByKeys(areaIds);

        List<Integer> parentIds = areas.stream().map(BaseArea::getParentId).distinct().collect(Collectors.toList());

        // 查询父区域
        List<BaseArea> parentAreas = baseAreaService.findByKeys(parentIds);

        List<Integer> pprentIds = parentAreas.stream().map(BaseArea::getParentId).distinct().collect(Collectors.toList());

        // 查询父区域的上级区域
        List<BaseArea> pparentAreas = baseAreaService.findByKeys(pprentIds);

        // 合并父子区域
        List<BaseArea> allAreas = Stream.of(areas, parentAreas, pparentAreas).flatMap(p -> p.stream()).collect(Collectors.toList());

        // 区域Map
        Map<Integer, BaseArea> areaMap = allAreas.stream().collect(Collectors.toMap(p -> p.getAreaId(), p -> p, (p, u) -> p));

        List<ChannelServiceArea> list = areaIds.stream().map(areaId -> {
            BaseArea baseArea = areaMap.get(areaId);
            ChannelServiceArea serviceArea = null;
            if (baseArea.getLevel() == 3) {
                // 当前区域为市
                // 获取省
                BaseArea province = Optional.ofNullable(areaMap.get(baseArea.getParentId())).orElse(new BaseArea());
                serviceArea = new ChannelServiceArea(null, channelId, province.getAreaId(), baseArea.getAreaId(), null, province.getName(), baseArea.getName(), null, null, null,
                        baseArea.getLatitude(), baseArea.getLongitude(), null, operator, operator, DateUtil.getNow(), DateUtil.getNow());
            } else if (baseArea.getLevel() == 4) {
                // 当前区域为区
                // 获取市
                BaseArea city = Optional.ofNullable(areaMap.get(baseArea.getParentId())).orElse(new BaseArea());
                // 获取省
                BaseArea province = null;
                if (city.getParentId() == 1) {
                    // 如果市的上级为全国则省ID为市ID
                    province = city;
                } else {
                    province = Optional.ofNullable(areaMap.get(city.getParentId())).orElse(new BaseArea());
                }
                serviceArea = new ChannelServiceArea(null, channelId, province.getAreaId(), city.getAreaId(), baseArea.getAreaId(), province.getName(), city.getName(), baseArea.getName(), null, null,
                        baseArea.getLatitude(), baseArea.getLongitude(), null, operator, operator, DateUtil.getNow(), DateUtil.getNow());
            }
            return serviceArea;
        }).collect(Collectors.toList());

        serviceAreaService.insertBatch(list);
        createLog(channelId, null, TAB_KTQY, null);

    }

    @Override
    public void addAllCityServiceArea(Integer channelId, String operator) {
        List<Integer> allCityIds = baseAreaService.listAllCity().stream().map(DictModel::getKey).collect(Collectors.toList());
        addServiceArea(allCityIds, channelId, operator);
        createLog(channelId, null, TAB_KTQY, null);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteServiceArea(List<Integer> serviceAreaIds, String operator) {
        Integer serviceAreaId = serviceAreaIds.get(0);
        ChannelServiceArea serviceArea = serviceAreaService.findByKey(serviceAreaId);
        serviceAreaService.deleteByKeys(serviceAreaIds);
        areaCategoryService.deleteByServiceAreaIds(serviceAreaIds, null);
        createLog(serviceArea.getChannelId(), null, TAB_KTQY_YCQY, null);
    }

    @Override
    public List<KvDTO<Integer, String>> listAllLevelCategoryByChannelId(Integer channelId, Integer showType) {
        if (NumberUtil.isNullOrZero(channelId) || NumberUtil.isNullOrZero(showType)) {
            log.error("渠道ID和showType不能为空");
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PANAM_NULL);
        }
        try {
            channelId = channelServiceCategoryBService.getAvailableCategoryChannelId(channelId);
        } catch (PlatException e) {
            return Collections.emptyList();
        }
        // 查询渠道服务分类
        // 如果二级渠道没有有效数据，则继承一级渠道
        List<ChannelServiceCategory> categoryList = categoryService.listByChannelId(channelId, showType);
        List<String> categIdAll = categoryList.stream()
                .map(p -> servToStr(p))
                .collect(Collectors.toList());

        List<ServAssCategoryVO> voList = listServCategoryByShowType(showType).stream()
                .filter(p -> categIdAll.contains(servToStr(p)))
                .collect(Collectors.toList());
        return listAllChildCategory(voList);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void modifyDrawChannelAreaMap(ChannelServiceArea vo) {
        serviceAreaService.updateByKey(vo);
        ChannelServiceArea byKey = serviceAreaService.findByKey(vo.getServiceAreaId());
        createLog(byKey.getChannelId(), null, TAB_KTQY_XGDT, null);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void modifyCommissions(List<ChannelCommission> commissions, String operator) {
        for (ChannelCommission commission : commissions) {
            modifyCommission(commission, operator);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void modifyCommission(ChannelCommission commission, String operator) {
        Integer channelId = commission.getChannelId();
        Integer servCategId = commission.getServCategId();
        boolean flag = commission.getEffectiveTime().getTime() <= DateUtil.getNow().getTime();
        if (flag) {
            commission.setCommissionCurrent(commission.getCommissionNew());
            commission.setCommissionType(commission.getCommissionTypeNew());
            commission.setBaseType(commission.getBaseTypeNew());
            commission.setCommissionNew(null);
            commission.setCommissionTypeNew(null);
            commission.setBaseTypeNew(null);
            commission.setEffectiveTime(null);
        }
        ChannelCommission findBy = commissionService.findByChannelIdAndServCategId(channelId, servCategId);
        if (findBy != null) {
            commission.setId(findBy.getId());
            commission.setUpdater(operator);
            // 修改
            if (flag) {
                // 如果立即生效则相关new字段设置为null
                commissionService.updateByKey(commission);
            } else {
                // 非立即生效则修改new字段，current不传则不修改
                commissionService.updateByKeySelective(commission);
            }
        } else {
            // 新增
            commission.setCreater(operator);
            commission.setUpdater(operator);
            commissionService.insert(commission);
        }
        createLog(commission.getChannelId(), null, TAB_YJSZ, null);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void modifySettle(ChannelSettle settle, String operator) {

        ChannelMergeSettle mergeSettle = mergeSettleService.findById(settle.getChannelId());

        if (settle.getStatementMode() != null && settle.getStatementMode() != ChannelStatementModeEnum.CONSTS_HALF_MONTH) {
            settle.setStatementGenerateTimeSecond(null);
            settle.setStatementEndTimeSecond(null);
        }

        ChannelSettle byKey = settleService.findByKey(settle.getChannelId());
        if (byKey == null) {
            settle.setCreater(operator);
            settle.setUpdater(operator);
            settleService.insert(settle);
        } else {
            // 排除带*的数据
            if (StringUtil.isNotBlank(settle.getFinancerPhone()) && settle.getFinancerPhone().indexOf("*") != -1) {
                settle.setFinancerPhone(byKey.getFinancerPhone());
            }
            if (StringUtil.isNotBlank(settle.getBankAccount()) && settle.getBankAccount().indexOf("*") != -1) {
                settle.setBankAccount(byKey.getBankAccount());
            }
            if (StringUtil.isNotBlank(settle.getAlipayAccount()) && settle.getAlipayAccount().indexOf("*") != -1) {
                settle.setAlipayAccount(byKey.getAlipayAccount());
            }
            if (StringUtil.isNotBlank(settle.getWechatAccount()) && settle.getWechatAccount().indexOf("*") != -1) {
                settle.setWechatAccount(byKey.getWechatAccount());
            }
            settle.setUpdater(operator);
            settleService.updateByKey(settle);
            ChannelSettle after = settleService.findByKey(settle.getChannelId());
            // 保存渠道结算日志 yangshuangping 2021-7-2 11:51:23
            byKey.setMergeSettle(Objects.isNull(mergeSettle) ? settle.getMergeSettle() : mergeSettle.getMergeSettle());
            after.setMergeSettle(settle.getMergeSettle());

            String[] compareContentData = getCompareContentData(byKey, after);
            createLog(settle.getChannelId(), null, TAB_JSXX, compareContentData[1]);
            // redis key 删除
            String key = RedisKeyConstant.getKeyChannelSettleDro(settle.getChannelId());
            redisTemplate.delete(key);
        }
        if (settle.getStatementMode() != null && (byKey == null || isModifyStatement(byKey, settle))) {
            sendMQSettle(settle);
        }
        // 合并结算
        Channel channel = channelService.findByKey(settle.getChannelId());
        if (channel != null && channel.getCompanyId() != null && settle.getStatementMode() != null && settle.getStatementGenerateTime() != null && settle.getStatementEndTime() != null && settle.getMergeSettle() != null && settle.getStatementChannel() != null) {
            String mergeMark = ChannelMergeSettle.generateMergeMark(channel.getCompanyId(), settle.getStatementMode(), settle.getStatementGenerateTime(), settle.getStatementEndTime(), settle.getStatementChannel());
            if (mergeSettle == null) {
                mergeSettle = ChannelMergeSettle.builder()
                        .channelId(settle.getChannelId())
                        .mergeSettle(settle.getMergeSettle())
                        .mergeMark(mergeMark)
                        .creater(operator)
                        .build();
                mergeSettleService.insert(mergeSettle);
            } else {
                mergeSettle.setMergeMark(mergeMark);
                mergeSettle.setMergeSettle(settle.getMergeSettle());
                mergeSettle.setUpdater(operator);
                mergeSettle.setUpdateTime(new Date());
                mergeSettleService.updateByKey(mergeSettle);
            }
        }
    }

    private void sendMQSettle(ChannelSettle settle) {
        // 修改结算周期或时间
        Integer channelId = settle.getChannelId();
        ChannelSettleDTO dto = new ChannelSettleDTO();
        dto.setStatementObjId(channelId);
        dto.setPlat(settle.getPlat());
        dto.setStatementMode(settle.getStatementMode());
        dto.setStatementGenerateTime(settle.getStatementGenerateTime());
        dto.setStatementEndTime(settle.getStatementEndTime());
        dto.setStatementGenerateTimeSecond(settle.getStatementGenerateTimeSecond());
        dto.setStatementEndTimeSecond(settle.getStatementEndTimeSecond());

        String randomKey = StringUtil.getRandomsString(32);
        log.info("sending countCycle mq--->" + "countCycleMqTopic=" + countCycleMqTopic + ",countCycleMqTags=" + ERP_CHANNEL_STATEMENT_CONFIG_MQ_TAG + ",ChannelSettleDTO=" + dto + ",randomKey="
                + randomKey);
        zmnMQSender.send(countCycleMqTopic, ERP_CHANNEL_STATEMENT_CONFIG_MQ_TAG, randomKey, JSON.toJSONString(dto));
    }

    @Override
    public boolean initSendMQSettle(String operator) {
        List<ChannelSettle> channelSettles = settleService.listWithLevelTwo();
        log.info("init channel settle");
        for (ChannelSettle channelSettle : channelSettles) {
            if (channelSettle.getStatementMode() != null) {
                sendMQSettle(channelSettle);
            }
        }
        log.info("init channel settle end");
        return true;
    }

    @Override
    @SuppressWarnings("Duplicates")
    public boolean checkNotifyEngineer(Integer channelId) throws PlatException {
        ChannelOrderConfig channelOrderConfig = channelOrderConfigService.findByKey(channelId);

        // 如果二级渠道没有订单配置数据，则查询一级渠道的订单配置数据
        if (Objects.isNull(channelOrderConfig)) {
            Channel channel = channelService.findByKey(channelId);
            if (Objects.equals(channel.getRank(), ChannelDict.RANK_TWO) && NumberUtil.isPositiveInteger(channel.getParentId())) {
                channelOrderConfig = channelOrderConfigService.findByKey(channel.getParentId());
            }
        }

        if (Objects.isNull(channelOrderConfig)) {
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_CHANNEL_NO_ORDER_CONFIG);
        }

        if (Objects.equals(GlobalConsts.YES, channelOrderConfig.getNotifyEngineer())) {
            return true;
        }

        return false;
    }

    @Override
    @SuppressWarnings("Duplicates")
    public boolean checkShowOrderPrice(Integer channelId) throws PlatException {
        ChannelOrderConfig channelOrderConfig = channelOrderConfigService.findByKey(channelId);

        // 如果二级渠道没有订单配置数据，则查询一级渠道的订单配置数据
        if (Objects.isNull(channelOrderConfig)) {
            Channel channel = channelService.findByKey(channelId);
            if (Objects.equals(channel.getRank(), ChannelDict.RANK_TWO) && NumberUtil.isPositiveInteger(channel.getParentId())) {
                channelOrderConfig = channelOrderConfigService.findByKey(channel.getParentId());
            }
        }

        if (Objects.isNull(channelOrderConfig)) {
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_CHANNEL_NO_ORDER_CONFIG);
        }

        if (Objects.equals(GlobalConsts.YES, channelOrderConfig.getShowOrderPrice())) {
            return true;
        }

        return false;
    }

    private boolean isModifyStatement(ChannelSettle oldSettle, ChannelSettle newSettle) {
        if (!Objects.equals(oldSettle.getStatementMode(), newSettle.getStatementMode())) {
            return true;
        }
        if (!Objects.equals(oldSettle.getStatementGenerateTime(), newSettle.getStatementGenerateTime())) {
            return true;
        }
        if (!Objects.equals(oldSettle.getStatementEndTime(), newSettle.getStatementEndTime())) {
            return true;
        }
        if (!Objects.equals(oldSettle.getStatementGenerateTimeSecond(), newSettle.getStatementGenerateTimeSecond())) {
            return true;
        }
        if (!Objects.equals(oldSettle.getStatementEndTimeSecond(), newSettle.getStatementEndTimeSecond())) {
            return true;
        }
        return false;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @SuppressWarnings("Duplicates")
    public void modifyChannelRatio(ChannelCityPriceRatioVo channelCityPriceRatio, String operator) {
        Date now = DateUtil.getNow();
        ChannelCityPriceRatioQuery channelCityPriceRatioQuery = new ChannelCityPriceRatioQuery();
        channelCityPriceRatioQuery.setChannelId(channelCityPriceRatio.getChannelId());
        channelCityPriceRatioQuery.setPriceType(channelCityPriceRatio.getPriceType());
        channelCityPriceRatioQuery.setRatioType(ChannelCityRatioTypeEnum.CHANNELRATIO.getCode());
        channelCityPriceRatioQuery.setBizType(channelCityPriceRatio.getBizType());
        ChannelCityPriceRatio queryResult = cityPriceRatioService.findByChannelIdAndCityAndCategAndType(channelCityPriceRatioQuery);
        Double toBeEffectiveRatio = channelCityPriceRatio.getToBeEffectiveRatio();

        Integer bizType = channelCityPriceRatio.getBizType();
        if (bizType == ProductConsts.BIZ_TYPE_C) {
            // C类业务价格系数时新增修改计价器3.0默认系数
            channelCityPriceRatioQuery.setRatioType(ChannelCityRatioTypeEnum.CHANNELCITYMETER3RATIO.getCode());
            ChannelCityPriceRatio queryResultM = cityPriceRatioService.findByChannelIdAndCityAndCategAndType(channelCityPriceRatioQuery);
            Double meterToBeEffectiveRatio = channelCityPriceRatio.getMeterToBeEffectiveRatio();
            if (queryResultM == null) {
                if (NumberUtil.isNotNullOrZero(meterToBeEffectiveRatio)) {
                    ChannelCityPriceRatio createOneRatioM = new ChannelCityPriceRatio();
                    BeanUtils.copyProperties(channelCityPriceRatio, createOneRatioM);
                    createOneRatioM.setToBeEffectiveRatio(meterToBeEffectiveRatio);
                    createOneRatioM.setCreater(operator);
                    createOneRatioM.setUpdater(operator);
                    createOneRatioM.setCreateTime(now);
                    createOneRatioM.setUpdateTime(now);
                    createOneRatioM.setRatioType(ChannelCityRatioTypeEnum.CHANNELCITYMETER3RATIO.getCode());
                    cityPriceRatioService.insert(createOneRatioM);
                }
            } else {
                if (NumberUtil.isNullOrZero(queryResultM.getRatio()) && NumberUtil.isNullOrZero(meterToBeEffectiveRatio)) {
                    cityPriceRatioService.deleteByKey(queryResultM.getRatioId());
                } else {
                    queryResultM.setToBeEffectiveRatio(meterToBeEffectiveRatio);
                    queryResultM.setUpdateTime(DateUtil.getNow());
                    queryResultM.setUpdater(operator);
                    queryResultM.setEffectiveDate(channelCityPriceRatio.getEffectiveDate());
                    cityPriceRatioService.updateByKey(queryResultM);
                }
            }
        }


        if (queryResult == null) {
            if (toBeEffectiveRatio != null) {
                ChannelCityPriceRatio createOneRatio = new ChannelCityPriceRatio();
                BeanUtils.copyProperties(channelCityPriceRatio, createOneRatio);
                createOneRatio.setCreater(operator);
                createOneRatio.setUpdater(operator);
                createOneRatio.setCreateTime(now);
                createOneRatio.setUpdateTime(now);
                createOneRatio.setRatioType(ChannelCityRatioTypeEnum.CHANNELRATIO.getCode());
                cityPriceRatioService.insert(createOneRatio);
            }
        } else {
            if (queryResult.getRatio() == null && toBeEffectiveRatio == null) {
                cityPriceRatioService.deleteByKey(queryResult.getRatioId());
            } else {
                queryResult.setToBeEffectiveRatio(toBeEffectiveRatio);
                queryResult.setUpdateTime(DateUtil.getNow());
                queryResult.setUpdater(operator);
                queryResult.setEffectiveDate(channelCityPriceRatio.getEffectiveDate());
                cityPriceRatioService.updateByKey(queryResult);
            }
        }

        createLog(channelCityPriceRatio.getChannelId(), null, getPriceLogTag(channelCityPriceRatio.getBizType()), null);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @SuppressWarnings("Duplicates")
    public void modifyChannelDiscount(ChannelCityPriceRatio channelCityPriceRatio, String operator) {
        Date now = DateUtil.getNow();
        ChannelCityPriceRatioQuery channelCityPriceRatioQuery = new ChannelCityPriceRatioQuery();
        channelCityPriceRatioQuery.setBizType(channelCityPriceRatio.getBizType());
        channelCityPriceRatioQuery.setPriceType(channelCityPriceRatio.getPriceType());
        channelCityPriceRatioQuery.setRatioType(ChannelCityRatioTypeEnum.DISCOUNTRATIO.getCode());
        channelCityPriceRatioQuery.setChannelId(channelCityPriceRatio.getChannelId());
        ChannelCityPriceRatio queryResult = cityPriceRatioService.findByChannelIdAndCityAndCategAndType(channelCityPriceRatioQuery);

        Double toBeEffectiveRatio = channelCityPriceRatio.getToBeEffectiveRatio();

        if (queryResult == null) {
            if (toBeEffectiveRatio != null) {
                ChannelCityPriceRatio createOneRatio = new ChannelCityPriceRatio();
                createOneRatio = channelCityPriceRatio;
                createOneRatio.setCreater(operator);
                createOneRatio.setUpdater(operator);
                createOneRatio.setCreateTime(now);
                createOneRatio.setUpdateTime(now);
                createOneRatio.setRatioType(ChannelCityRatioTypeEnum.DISCOUNTRATIO.getCode());
                cityPriceRatioService.insert(createOneRatio);
            }
        } else {
            if (queryResult.getRatio() == null && toBeEffectiveRatio == null) {
                cityPriceRatioService.deleteByKey(queryResult.getRatioId());
            } else {
                queryResult.setToBeEffectiveRatio(toBeEffectiveRatio);
                queryResult.setUpdateTime(DateUtil.getNow());
                queryResult.setUpdater(operator);
                queryResult.setEffectiveDate(channelCityPriceRatio.getEffectiveDate());
                cityPriceRatioService.updateByKey(queryResult);
            }
        }

        createLog(channelCityPriceRatio.getChannelId(), null, getPriceLogTag(channelCityPriceRatio.getBizType()), null);
    }

    @Override
    public void modifyUpdateTimeByKey(Integer channelId, String operator) {
        Channel channel = new Channel();
        channel.setChannelId(channelId);
        channel.setUpdateTime(DateUtil.getNow());
        channel.setUpdater(operator);
        channelService.updateByKeySelective(channel);
    }

    /**
     * 记录渠道操作日志
     *
     * @param channelId
     * @param channelName
     * @param content
     * @param data
     */
    @Override
    public void createLog(Integer channelId, String channelName, String content, String data) {
        createLog(channelId, channelName, content, data, crdaterByDeptAndTel(), null);
    }

    /**
     * 记录渠道操作日志
     *
     * @param channelId   渠道ID
     * @param channelName 渠道名称
     * @param content     操作内容
     * @param data        操作数据:json值
     * @param remark      备注
     */
    @Override
    public void createLog(Integer channelId, String channelName, String content, String data, String remark) {
        createLog(channelId, channelName, content, data, crdaterByDeptAndTel(), remark);
    }

    /**
     * 获取操作人
     *
     * @return 管理员-系统管理部-1341****674
     */
    private String crdaterByDeptAndTel() {
        String creater = null;
        try {
            LoginStaff loginStaff = StaffAdminService.currentStaff();
            creater = loginStaff.getDeptName() + "-" + loginStaff.getRealName();
        } catch (Exception e) {
            log.error("createLog getStaff is error! defaultStaff: SYSTEM");
            creater = "SYSTEM";
        }
        return creater;
    }

    @Override
    public void createLog(Integer channelId, String channelName, String content, String data, String creater, String remark) {
        ChannelLog channelLog = new ChannelLog();
        channelLog.setChannelId(channelId);
        channelLog.setChannelName(channelName);
        channelLog.setType(LOG_TYPE_UPDATE);
        channelLog.setContent(content);
        channelLog.setData(data);
        channelLog.setCreater(creater);
        channelLog.setCreateTime(DateUtil.getNow());
        channelLog.setRemark(remark);
        channelLogService.insert(channelLog);
    }

    @Override
    public <T> String[] getCompareContentData(T before, T after) {
        // 比较出差异字段
        List<CompareObjectUtil.CompareField> compareFields = CompareObjectUtil.compareObj(after, before);
        // 修改值
        String data = JSON.toJSONString(compareFields);
        return new String[]{"", data};
    }

    private String getPriceLogTag(Integer bizType) {
        if (Objects.equals(ProductConsts.BIZ_TYPE_C, bizType)) {
            return TAB_BWJG;
        } else if (Objects.equals(ProductConsts.BIZ_TYPE_F, bizType)) {
            return TAB_BNJG;
        } else if (Objects.equals(ProductConsts.BIZ_TYPE_B, bizType)) {
            return TAB_GCJG;
        }

        return "";
    }

    /**
     * 渠道E特殊处理，临时使用
     */
    private enum ChanenlSpecialTreatment {

        /**
         * 城市为 重庆、深圳、南昌、成都，开通(水电维修-砖缝修缮-瓷砖)，其他城市不开通
         */
        TREATMENT_A(32837, Arrays.asList(500100, 440300, 360100, 510100), 1007, 2981, 2982, "砖缝修缮", "瓷砖", 2979, 2980),

        /**
         * 城市为 南宁、昆明，开通(清洁杀菌-家具门窗-门窗)，其他城市不开通
         */
        TREATMENT_B(32837, Arrays.asList(450100, 530100), 1020, 2692, 2825, "家具门窗", "门窗", 2985, 2988),
        ;

        ChanenlSpecialTreatment(Integer channelId, List<Integer> cityIds, Integer servCategId, Integer categOneId, Integer categTwoId, String categOneName, String categTwoName, Integer categOneIdBack,
                                Integer categTwoIdBack) {
            this.channelId = channelId;
            this.cityIds = cityIds;
            this.servCategId = servCategId;
            this.categOneId = categOneId;
            this.categTwoId = categTwoId;
            this.categOneName = categOneName;
            this.categTwoName = categTwoName;
            this.categOneIdBack = categOneIdBack;
            this.categTwoIdBack = categTwoIdBack;
        }

        private Integer channelId;
        private List<Integer> cityIds;
        private Integer servCategId;
        private Integer categOneId;
        private Integer categTwoId;
        private String categOneName;
        private String categTwoName;
        private Integer categOneIdBack;
        private Integer categTwoIdBack;

        public static void treatment(Integer channelId, Integer cityId, Integer showType, Integer servCategId, List<CategoryInfoDTO> list, BaseCategoryService baseCategoryService) {
            for (ChanenlSpecialTreatment cst : values()) {
                // 渠道E特殊处理
                if (Objects.equals(cst.channelId, channelId) && Objects.equals(cst.servCategId, servCategId)) {
                    treatment(cityId, showType, list, baseCategoryService, cst);
                }
            }
        }

        public static void treatment(Integer channelId, Integer cityId, Integer showType, List<Integer> servCategIds, List<CategoryInfoDTO> list, BaseCategoryService baseCategoryService) {
            for (ChanenlSpecialTreatment cst : values()) {
                // 渠道E特殊处理
                if (Objects.equals(cst.channelId, channelId) && servCategIds.contains(cst.servCategId)) {
                    treatment(cityId, showType, list, baseCategoryService, cst);
                }
            }
        }

        private static void treatment(Integer cityId, Integer showType, List<CategoryInfoDTO> list, BaseCategoryService baseCategoryService, ChanenlSpecialTreatment cst) {
            List<Integer> categIdList = list.stream().map(CategoryInfoDTO::getCategId).collect(Collectors.toList());
            if (cst.cityIds.contains(cityId)) {
                if (!categIdList.contains(cst.categTwoId) && Objects.equals(showType, ProductConsts.EC_PRODUCT_TYPE)) {
                    BaseCategory baseCategory = baseCategoryService.findByKey(cst.categTwoId);
                    BaseCategory baseCategoryOne = baseCategoryService.findByKey(cst.categOneId);
                    list.add(new CategoryInfoDTO(cst.categTwoId, cst.categTwoName, baseCategory.getSort(), baseCategory.getStatus(), cst.categOneId, cst.categOneName, baseCategoryOne.getSort(),
                            baseCategoryOne.getStatus(), baseCategory.getIcon(), baseCategory.getDetailName(), baseCategory.getTariffName(), baseCategory.getTariffStatus(), baseCategory.getSimpleSpell(), baseCategoryOne.getSimpleSpell()));
                }
                if (!categIdList.contains(cst.categTwoIdBack) && Objects.equals(showType, ProductConsts.ERP_PRODUCT_TYPE)) {
                    BaseCategory baseCategory = baseCategoryService.findByKey(cst.categTwoIdBack);
                    BaseCategory baseCategoryOne = baseCategoryService.findByKey(cst.categOneIdBack);
                    list.add(new CategoryInfoDTO(cst.categTwoIdBack, cst.categTwoName, baseCategory.getSort(), baseCategory.getStatus(), cst.categOneIdBack, cst.categOneName,
                            baseCategoryOne.getSort(), baseCategoryOne.getStatus(), baseCategory.getIcon(), baseCategory.getDetailName(), baseCategory.getTariffName(), baseCategory.getTariffStatus(), baseCategory.getSimpleSpell(), baseCategoryOne.getSimpleSpell()));
                }
            } else {
                if (categIdList.contains(cst.categTwoId) && Objects.equals(showType, ProductConsts.EC_PRODUCT_TYPE)) {
                    for (int i = 0; i < list.size(); i++) {
                        if (Objects.equals(list.get(i).getCategId(), cst.categTwoId)) {
                            list.remove(list.get(i));
                            break;
                        }
                    }
                }
                if (categIdList.contains(cst.categTwoIdBack) && Objects.equals(showType, ProductConsts.ERP_PRODUCT_TYPE)) {
                    for (int i = 0; i < list.size(); i++) {
                        if (Objects.equals(list.get(i).getCategId(), cst.categTwoIdBack)) {
                            list.remove(list.get(i));
                            break;
                        }
                    }
                }
            }
        }

    }

    /**
     * 描述: 发送渠道消息给资金账户开户
     *
     * @param channel 渠道
     * @param type    处理类型：1新增，2修改
     * @author guoqiao
     * @since 2021/5/10 10:53
     */
    private void sendChannelOpenAccount(Channel channel, Integer type, LoginStaff mcStaff) {

        if (channel == null || NumberUtil.isNullOrZero(type)) {
            log.info("参数不合法");
            return;
        }
        try {
            OpenAccountDIO dio = new OpenAccountDIO();
            dio.setHandleType(type);
            dio.setIdentityId(IdentityConsts.ACCOUNT_IDENTITY_ID_CHANNEL);
            dio.setIdentityObjectId(Long.valueOf(channel.getChannelId()));
            dio.setIdentityObjectName(channel.getName());
            dio.setPlat(channel.getPlat());
            dio.setOperatorType(mcStaff.getType());
            dio.setOperatorId(Long.valueOf(mcStaff.getStaffId()));
            dio.setOperator(mcStaff.getRealName());
            log.warn("发送消息->渠道资金账户开户,message:{}", dio);
            zmnMQSender.send(platTopicAccount, AccountMqConsts.OPENING_ACCOUNT_TAG, channel.getChannelId().toString(), JSONObject.toJSONString(dio));
        } catch (ZmnMQException e) {
            log.error("发送消息->渠道资金账户开户失败,原因:{}", e.getMessage(), e);
        }
    }

    @Override
    public List<KvDTO<Integer, String>> listAllChildCategory(List<ServAssCategoryVO> list) {
        // 按服务分类分组
        Map<Integer, List<ServAssCategoryVO>> serviceCategoryMap = list.stream().collect(groupingBy(ServAssCategory::getServCategId));

        List<KvDTO<Integer, String>> ret = serviceCategoryMap.values().stream().map(serviceCategory -> {
            // 按一级分类分组
            Map<Integer, List<ServAssCategoryVO>> categoryOneMap = serviceCategory.stream().collect(groupingBy(ServAssCategory::getCategOneId));

            List<KvDTO> categoryOneList = categoryOneMap.values().stream().map(categoryOne -> {
                // 二级分类KvDTO
                List<KvDTO> categList = categoryOne.stream().map(p -> new KvDTO(p.getCategId(), p.getCategName())).collect(Collectors.toList());
                // 一级分类KvDTO
                KvDTO categOne = new KvDTO<>(categoryOne.get(0).getCategOneId(), categoryOne.get(0).getCategOneName());
                categOne.setChildren(categList);
                return (KvDTO<Integer, String>) categOne;
            }).collect(Collectors.toList());

            // 服务分类KvDTO
            KvDTO dto = new KvDTO<>(serviceCategory.get(0).getServCategId(), serviceCategory.get(0).getServCategName());
            dto.setChildren(categoryOneList);
            return (KvDTO<Integer, String>) dto;
        }).collect(Collectors.toList());
        return ret;
    }

    @Override
    public List<ServAssCategoryVO> listServCategoryByShowType(Integer showType) {
        if (NumberUtil.isNullOrZero(showType)) {
            return new ArrayList<>();
        }
        ServAssCategoryQuery servAssCategoryQuery = new ServAssCategoryQuery();
        servAssCategoryQuery.setCategOneStatus(GlobalConsts.YES);
        servAssCategoryQuery.setCategTwoStatus(GlobalConsts.YES);
        servAssCategoryQuery.setShowType(showType);

        if (ProductConsts.EC_PRODUCT_TYPE.equals(showType)) {
            servAssCategoryQuery.setServCategShowStatus(GlobalConsts.YES);
        } else {
            servAssCategoryQuery.setServCategStatus(GlobalConsts.YES);
        }
        return Optional.ofNullable(servAssCategoryService.listByQuery(servAssCategoryQuery)).orElse(new ArrayList<>());
    }

    /**
     * 描述: 根据渠道实体设置上级来院渠道名称
     *
     * @param before 修改前实体
     * @param after  修改后实体
     * @author yangshuangping
     * @since 2021/7/2 11:03
     **/
    private void getsTheSourceChannelName(Channel before, Channel after) {
        // listNameByChannelIds 渠道日志设置上级来源渠道名称
        List<Integer> ids = Lists.newArrayList(before.getParentSourceId(), after.getParentSourceId());
        Map<Integer, String> parentSourceName = Optional.ofNullable(channelService.listNameByChannelIds(ids).stream()
                .collect(Collectors.toMap(ChannelIdAndName::getChannelId, ChannelIdAndName::getName))).orElse(null);
        if (Objects.nonNull(parentSourceName)) {
            before.setParentSourceName(parentSourceName.get(before.getParentSourceId()));
            after.setParentSourceName(parentSourceName.get(after.getParentSourceId()));

        }
    }

    /**
     * 将服务分类转为以“-” 分隔的字符串
     *
     * @param bean 实体
     * @param <T>  类型
     * @return 1001-2001-2003
     */
    public <T> String servToStr(T bean) {
        CategotyVO map = Optional.ofNullable(BeanMapper.map(bean, CategotyVO.class)).orElse(null);
        return Objects.isNull(map) ? "" : new StringBuffer().append(map.getServCategId())
                .append(OnePriceConsts.SPLITER_STRIPING)
                .append(map.getCategOneId())
                .append(OnePriceConsts.SPLITER_STRIPING)
                .append(map.getCategId()).toString();

    }

    @Override
    public void copyChannelSendChannelOpenAccount(Integer channelId, LoginStaff mcStaff) {
        Channel channel = channelService.findByKey(channelId);
        this.sendChannelOpenAccount(channel, GlobalConsts.NO, mcStaff);
    }
}
